#include "Matrix.h"
#pragma unmanaged
#include <cmath>

Vector4::Vector4() {
	for(int i=0; i<4; i++) vector[i]=0.0f;
}

void Vector4::operator=(Vector4 &v) {
	
	for(int i=0; i<4; i++) vector[i]=v.vector[i];
	
}

Vector4 Vector4::operator+(Vector4 &v) {
	Vector4 r;
	for(int i=0; i<4; i++) r.vector[i]=vector[i]+v.vector[i];
	return r;
}

Vector4 Vector4::operator-(Vector4 &v) {
	Vector4 r;
	for(int i=0; i<4; i++) r.vector[i]=vector[i]-v.vector[i];
	return r;
}

Vector4 Vector4::operator*(float s)
{
	Vector4 r;
	for(int i=0; i<4; i++) r.vector[i]=vector[i]*s;
	return r;
}

float Vector4::SculMul(Vector4 &v)
{
	float r=0.0f;
	for(int i=0; i<4; i++) r=r+vector[i]*v.vector[i];
	return r;
}

Vector3::Vector3() {
	for(int i=0; i<3; i++) vector[i]=0.0f;
}

void Vector3::operator=(Vector3 &v) {
	
	for(int i=0; i<3; i++) vector[i]=v.vector[i];
	
}

Vector3 Vector3::operator+(Vector3 &v) {
	Vector3 r;
	for(int i=0; i<3; i++) r.vector[i]=vector[i]+v.vector[i];
	return r;
}

Vector3 Vector3::operator-(Vector3 &v) {
	Vector3 r;
	for(int i=0; i<3; i++) r.vector[i]=vector[i]-v.vector[i];
	return r;
}

Vector3 Vector3::operator*(float s)
{
	Vector3 r;
	for(int i=0; i<3; i++) r.vector[i]=vector[i]*s;
	return r;
}

float Vector3::SculMul(Vector3 &v)
{
	float r=0.0f;
	for(int i=0; i<4; i++) r=r+vector[i]*v.vector[i];
	return r;
}

Vector3 Vector3::operator*(Vector3 &v) {
	Vector3 r;
	r.vector[0]=vector[1]*v.vector[2]-vector[2]*v.vector[1];
	r.vector[1]=vector[2]*v.vector[0]-vector[0]*v.vector[2];
	r.vector[2]=vector[0]*v.vector[1]-vector[1]*v.vector[0];
	return r;
}

float Vector3::Module() {
	return sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2]);
}

Vector3 Vector3::Normalize() {
	Vector3 r;
	float n=this->Module();
	r.vector[0]=vector[0]/n;
	r.vector[1]=vector[1]/n;
	r.vector[2]=vector[2]/n;
	return r;
}

Matrix4x4::Matrix4x4()
{
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
}

void Matrix4x4::Projection(float fovw, float fovh, float znear, float zfar)
{
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
	matrix[2][3]=1.0f;
	matrix[0][0]=cot(rad(fovw)/2);
	matrix[1][1]=cot(rad(fovh)/2);
	matrix[2][2]=zfar/(zfar-znear);
	matrix[3][2]=(-matrix[2][2])*znear;


}

void Matrix4x4::Translation(float x,float y, float z) {
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
	matrix[0][0]=1;
	matrix[1][1]=1;
	matrix[2][2]=1;
	matrix[3][3]=1;
	matrix[3][0]=x;
	matrix[3][1]=y;
	matrix[3][2]=z;
}

void Matrix4x4::Scaling(float sx, float sy, float sz) {
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
	matrix[0][0]=sx;
	matrix[1][1]=sy;
	matrix[2][2]=sz;
	matrix[3][3]=1;
}

void Matrix4x4::RotationX(float fx) {
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
	matrix[0][0]=1;
	matrix[3][3]=1;
	matrix[1][1]=cos(rad(fx));
	matrix[1][2]=sin(rad(fx));
	matrix[2][1]=(-sin(rad(fx)));
	matrix[2][2]=cos(rad(fx));
}

void Matrix4x4::RotationY(float fy) {
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
	matrix[1][1]=1;
	matrix[3][3]=1;
	matrix[0][0]=cos(rad(fy));
	matrix[0][2]=(-sin(rad(fy)));
	matrix[2][0]=sin(rad(fy));
	matrix[2][2]=cos(rad(fy));
}

void Matrix4x4::RotationZ(float fz) {
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
	matrix[2][2]=1;
	matrix[3][3]=1;
	matrix[0][0]=cos(rad(fz));
	matrix[0][1]=sin(rad(fz));
	matrix[1][0]=(-sin(rad(fz)));
	matrix[1][1]=cos(rad(fz));
}

void Matrix4x4::View(float x,float y, float z, float rotatex, float rotatey, float rotatez) {
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=0.0f;
	Vector3 XAxis, YAxis, ZAxis;
	Vector3 pEye, pAt, pUp;
	Vector4 up;
	Matrix4x4 m;
	pEye.vector[0]=x;
	pEye.vector[1]=y;
	pEye.vector[2]=z;
	up.vector[0]=0;
	up.vector[1]=1;
	up.vector[2]=0;
	up.vector[3]=0;
	m.RotationX(rotatex);
	up=m*up;
	m.RotationY(rotatey);
	up=m*up;
	m.RotationZ(rotatez);
	up=m*up;
	pUp.vector[0]=up.vector[0];
	pUp.vector[1]=up.vector[1];
	pUp.vector[2]=up.vector[2];
	ZAxis=pAt-pEye;
	ZAxis=ZAxis.Normalize();
	XAxis=pUp*ZAxis;
	XAxis=XAxis.Normalize();
	YAxis=ZAxis*XAxis;
	matrix[0][0]=XAxis.vector[0];
	matrix[1][0]=XAxis.vector[1];
	matrix[2][0]=XAxis.vector[2];
	matrix[3][0]=(-XAxis.SculMul(pEye));
	matrix[0][1]=YAxis.vector[0];
	matrix[1][1]=YAxis.vector[1];
	matrix[2][1]=YAxis.vector[2];
	matrix[3][1]=(-YAxis.SculMul(pEye));
	matrix[0][2]=ZAxis.vector[0];
	matrix[1][2]=ZAxis.vector[1];
	matrix[2][2]=ZAxis.vector[2];
	matrix[3][2]=(-ZAxis.SculMul(pEye));
	matrix[0][3]=0.0f;
	matrix[1][3]=0.0f;
	matrix[2][3]=0.0f;
	matrix[3][3]=1.0f;
}

inline float Matrix4x4::cot(float fov)
{
	return cos(fov)/sin(fov);
}

inline float Matrix4x4::rad(float fov)
{
	return fov*3.141592653f/180;
}

void Matrix4x4::operator=(Matrix4x4 &m)
{
	
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) matrix[i][j]=m.matrix[i][j];
	
}

Matrix4x4 Matrix4x4::operator+(Matrix4x4 &m) {
	Matrix4x4 r;
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) r.matrix[i][j]=matrix[i][j]+m.matrix[i][j];
	return r;
}

Matrix4x4 Matrix4x4::operator-(Matrix4x4 &m) {
	Matrix4x4 r;
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) r.matrix[i][j]=matrix[i][j]-m.matrix[i][j];
	return r;
}

Matrix4x4 Matrix4x4::operator*(Matrix4x4 &m) {
	Matrix4x4 r;
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++)
			for(int k=0; k<4; k++) r.matrix[i][j]=r.matrix[i][j]+matrix[i][k]*m.matrix[k][j];
	return r;
}

Matrix4x4 Matrix4x4::operator*(float s)
{
	Matrix4x4 r;
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) r.matrix[i][j]=matrix[i][j]*s;
	return r;
}

Vector4 Matrix4x4::operator*(Vector4 &v) {
	Vector4 r;
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++) r.vector[i]=r.vector[i]+matrix[i][j]*v.vector[j];
	return r;
}

void Matrix4x4::Transformation(float x, float y, float z,float sx, float sy, float sz, float fx, float fy, float fz) {
	Matrix4x4 t,s,rx,ry,rz;
	t.Translation(x,y,z);
	s.Scaling(sx,sy,sz);
	rx.RotationX(fx);
	ry.RotationY(fy);
	rz.RotationZ(fz);
	*this=t*s*rx*ry*rz;
	
}

#pragma managed